package modules.evaluator;

import java.io.BufferedReader;
import java.io.FileReader;

import miscellaneous.SequenceFileWriter;

public class SimulatedDatasetEvaluator {
	public SimulatedDatasetEvaluator() {
		
	}
	
	public int[] CalculateMembersInGroup (String path, String testFileInBCLFormat) {
		try {		
			int totalClusterSize = 0;
			int currentCluster = 0;
			BufferedReader bufferedreader;
			String str;

			bufferedreader = new BufferedReader(new FileReader(path + testFileInBCLFormat));
			while ((str = bufferedreader.readLine()) != null) 
				totalClusterSize++;
			bufferedreader.close();

			int[] temp = new int[totalClusterSize];
			bufferedreader = new BufferedReader(new FileReader(path + testFileInBCLFormat));
			while ((str = bufferedreader.readLine()) != null) {
				String[] strArr = str.split("\t");
				temp[currentCluster] = strArr.length;
				currentCluster++;
			}
			bufferedreader.close();
			return temp;
		} catch (Exception e) {
			System.out.println("CalculateMembersInGroup Failed : " + e.getMessage()); 
			System.exit(-1);
		}
		return null;
	}
	
	public int TotalMembersOfCluster (int[] array) {
		int sum = 0;
		for(int i = 0; i < array.length; i++)
			sum = sum + array[i];
		return sum;
	}
	
	public void qualityEvaluator(String testFileInBCLFormat, String path, String output, String software, String clusterFileName) {
		try {
			int[] familySize = CalculateMembersInGroup(path, testFileInBCLFormat);
			int total = TotalMembersOfCluster(familySize);
			
			SequenceFileWriter.writeAndAppendLine(path, output, "Quality results for " + software);

			int totalClusterSize = 0;
			int currentCluster = 0;
			BufferedReader bufferedreader;
			String str;

			bufferedreader = new BufferedReader(new FileReader(path + clusterFileName));
			while ((str = bufferedreader.readLine()) != null) 
				totalClusterSize++;
			bufferedreader.close();

			double[][] fMatrix = new double[familySize.length][totalClusterSize];
			int[][] clusterFamilyCounter = new int[familySize.length][totalClusterSize];

			bufferedreader = new BufferedReader(new FileReader(path + clusterFileName));
			while ((str = bufferedreader.readLine()) != null) { 
				for(int i = 0; i < familySize.length; i++) 
					clusterFamilyCounter[i][currentCluster] = 0;
				String[] strArr = str.split("\t");
				for(int i = 0; i < strArr.length; i++) 
					clusterFamilyCounter[Integer.parseInt(strArr[i])][currentCluster]++;
				for (int i = 0; i < familySize.length; i++) {
					double precision = (double)clusterFamilyCounter[i][currentCluster]/strArr.length;
					double recall = (double)clusterFamilyCounter[i][currentCluster]/(double)familySize[i];
					double fijValue = 0;
					if(precision != 0 || recall != 0)
						fijValue = ((double)2 * precision * recall)/(double)(precision + recall);
					fMatrix[i][currentCluster] = fijValue;
				}
				currentCluster++;
			}
			double[] fiArray = new double[familySize.length];
			double fScore = (double)0;

			for(int i = 0; i < familySize.length; i++) {
				double score = (double)0;
				for(int j = 0; j < totalClusterSize; j++) {
					fScore = fScore + (double)((double)clusterFamilyCounter[i][j] * fMatrix[i][j]/(double)total);
					score = score + (double)((double)clusterFamilyCounter[i][j] * fMatrix[i][j]/familySize[i]);
				}
				fiArray[i] = score;
			}

			for(int i = 0; i < familySize.length; i++) 
				SequenceFileWriter.writeAndAppendLine(path, output, String.valueOf(fiArray[i]));
			SequenceFileWriter.writeAndAppendLine(path, output, String.valueOf(fScore));
			SequenceFileWriter.writeAndAppendLine(path, output, String.valueOf(totalClusterSize));
		} catch (Exception e) {
			System.out.println("ClusterQualityEvaluator Failed : " + e.getMessage()); 
			System.exit(-1);
		}
	}
	
	public void precisionEvaluator(String testFileInBCLFormat, String path, String output, String software, String clusterFileName) {
		try {
			int[] familySize = CalculateMembersInGroup(path, testFileInBCLFormat);
			int total = TotalMembersOfCluster(familySize);
			
			SequenceFileWriter.writeAndAppendLine(path, output, "Precision results for " + software);

			int totalClusterSize = 0;
			int currentCluster = 0;
			BufferedReader bufferedreader;
			String str;

			bufferedreader = new BufferedReader(new FileReader(path + clusterFileName));
			while ((str = bufferedreader.readLine()) != null) 
				totalClusterSize++;
			bufferedreader.close();

			double[][] fMatrix = new double[familySize.length][totalClusterSize];
			int[][] clusterFamilyCounter = new int[familySize.length][totalClusterSize];

			bufferedreader = new BufferedReader(new FileReader(path + clusterFileName));
			while ((str = bufferedreader.readLine()) != null) { 
				for(int i = 0; i < familySize.length; i++) 
					clusterFamilyCounter[i][currentCluster] = 0;
				String[] strArr = str.split("\t");
				for(int i = 0; i < strArr.length; i++) 
					clusterFamilyCounter[Integer.parseInt(strArr[i])][currentCluster]++;
				for (int i = 0; i < familySize.length; i++) {
					double precision = (double)clusterFamilyCounter[i][currentCluster]/strArr.length;
					fMatrix[i][currentCluster] = precision;
				}
				currentCluster++;
			}
			double[] fiArray = new double[familySize.length];
			double fScore = (double)0;

			for(int i = 0; i < familySize.length; i++) {
				double score = (double)0;
				for(int j = 0; j < totalClusterSize; j++) {
					fScore = fScore + (double)((double)clusterFamilyCounter[i][j] * fMatrix[i][j]/(double)total);
					score = score + (double)((double)clusterFamilyCounter[i][j] * fMatrix[i][j]/familySize[i]);
				}
				fiArray[i] = score;
			}

			for(int i = 0; i < familySize.length; i++) 
				SequenceFileWriter.writeAndAppendLine(path, output, String.valueOf(fiArray[i]));
			SequenceFileWriter.writeAndAppendLine(path, output, String.valueOf(fScore));
			SequenceFileWriter.writeAndAppendLine(path, output, String.valueOf(totalClusterSize));
		} catch (Exception e) {
			System.out.println("ClusterPrecisionEvaluator Failed : " + e.getMessage()); 
			System.exit(-1);
		}
	}
	
	public void recallEvaluator(String testFileInBCLFormat, String path, String output, String software, String clusterFileName) {
		try {
			int[] familySize = CalculateMembersInGroup(path, testFileInBCLFormat);
			int total = TotalMembersOfCluster(familySize);
			
			SequenceFileWriter.writeAndAppendLine(path, output, "Recall results for " + software);

			int totalClusterSize = 0;
			int currentCluster = 0;
			BufferedReader bufferedreader;
			String str;

			bufferedreader = new BufferedReader(new FileReader(path + clusterFileName));
			while ((str = bufferedreader.readLine()) != null) 
				totalClusterSize++;
			bufferedreader.close();

			double[][] fMatrix = new double[familySize.length][totalClusterSize];
			int[][] clusterFamilyCounter = new int[familySize.length][totalClusterSize];

			bufferedreader = new BufferedReader(new FileReader(path + clusterFileName));
			while ((str = bufferedreader.readLine()) != null) { 
				for(int i = 0; i < familySize.length; i++) 
					clusterFamilyCounter[i][currentCluster] = 0;
				String[] strArr = str.split("\t");
				for(int i = 0; i < strArr.length; i++) 
					clusterFamilyCounter[Integer.parseInt(strArr[i])][currentCluster]++;
				for (int i = 0; i < familySize.length; i++) {
					double recall = (double)clusterFamilyCounter[i][currentCluster]/(double)familySize[i];
					fMatrix[i][currentCluster] = recall;
				}
				currentCluster++;
			}
			double[] fiArray = new double[familySize.length];
			double fScore = (double)0;

			for(int i = 0; i < familySize.length; i++) {
				double score = (double)0;
				for(int j = 0; j < totalClusterSize; j++) {
					fScore = fScore + (double)((double)clusterFamilyCounter[i][j] * fMatrix[i][j]/(double)total);
					score = score + (double)((double)clusterFamilyCounter[i][j] * fMatrix[i][j]/familySize[i]);
				}
				fiArray[i] = score;
			}

			for(int i = 0; i < familySize.length; i++) 
				SequenceFileWriter.writeAndAppendLine(path, output, String.valueOf(fiArray[i]));
			SequenceFileWriter.writeAndAppendLine(path, output, String.valueOf(fScore));
			SequenceFileWriter.writeAndAppendLine(path, output, String.valueOf(totalClusterSize));
		} catch (Exception e) {
			System.out.println("ClusterRecallEvaluator Failed : " + e.getMessage()); 
			System.exit(-1);
		}
	}
}
